//
//  EVEAPI.m
//  iEVEMon
//
//  http://myeve.eve-online.com/api/default.asp
//
//  Created by Scott Guyer on 3/22/08.
//  Copyright 2008 __MyCompanyName__. All rights reserved.
//


#import "EVEApi.h"
#import "Character.h"
#import "CharacterParser.h"
#import "CharListParser.h"
#import "TrainingSkillParser.h"
#import "Reachability.h"
#import "defs.h"


@implementation EVEApi

@synthesize userID;
@synthesize apiKey;
@synthesize charID;
@synthesize requestType;
@synthesize data;
@synthesize statusCode;

- (id) init
{
	requestType = 0;
	responseDelegate = nil;
	responseSelector = nil;
	userID = nil;
	apiKey = nil;
	data = [[NSMutableData alloc] initWithCapacity:1024];
	
	return self;
}

- (id) initWithUser:(NSString*)uid andKey:(NSString*)key 
{
	if ( (uid == nil) || (key == nil) )
		return nil;
	
	[self init];
		
	userID = [uid copy];
	apiKey = [key copy];
	
	return self;
}


- (void) setResponseDelegate:(id)delegate
{
//	if ( ! [delegate conformsToProtocol:@protocol(EVEAPIDelegate)] ) 
//	{ 
//		NSLog(@"invalid delegate; must conform to EVEAPIDelegate");
//		return;
//	} 
	
	responseDelegate = delegate;
}


- (void) cancel
{
	if ( conn == nil )
		return;
	
	NSLog(@"%s cancelling request 0x%x", __FUNCTION__, conn);
	
	[conn cancel];
	[conn release];
	conn = nil;
}


- (void) doPost:(NSString*)url withBody:(NSString*)body
{
	int timeout;
	
	if ( [[Reachability sharedReachability] internetConnectionStatus] == NotReachable )
		timeout = 30; // need extra time to establish connection
	else
		timeout = 10;
	
	NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]
		cachePolicy:NSURLRequestReloadIgnoringCacheData
		timeoutInterval:timeout];
	
	[request setHTTPMethod:@"POST"];
	[request addValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-type"];
	[request setHTTPBody:[body dataUsingEncoding:NSASCIIStringEncoding]];
	  
	conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
	if ( conn == nil )
	{
		NSLog(@"%s could not start the request", __FUNCTION__);
		// TODO: return status
	}
	
}


//
// fetch the current user's list of characters and character IDs.
// On success, we call the eveapiSuccess delegate with an NSDictionary
// object.  Keyed by character names, and values of character IDs.
//
- (void) getCharacters:(SEL)sel
{
	requestType = EVEAPIRequestTypeCharacterList;
	responseSelector = sel;
	
	[data setLength:0];
	
	NSString* body = [NSString stringWithFormat:@"userid=%@&apikey=%@", userID, apiKey];
	
	[self doPost:@"http://api.eve-online.com/account/Characters.xml.aspx" withBody:body];
}

//
// fetch the character data identified by the charID for the current user.
// On success we call the eveapiSuccess delegate with a Character object.
//
- (void) getCharacter:(NSString*)cid withCallback:(SEL)sel
{
	requestType = EVEAPIRequestTypeCharacter;
	responseSelector = sel;
	
	//charID = cid;
	charID = [cid copy];
	//[charID retain];
	
	[data setLength:0];
	
	NSString* body = [NSString stringWithFormat:@"userid=%@&apikey=%@&characterid=%@", userID, apiKey, cid];
	
	[self doPost:@"http://api.eve-online.com/char/CharacterSheet.xml.aspx" withBody:body];
}

//
// fetch the character data identified by the charID for the current user.
// On success we call the eveapiSuccess delegate with a Character object.
//
- (void) getTrainingSkill:(NSString*)cid withCallback:(SEL)sel
{
	requestType = EVEAPIRequestTypeSkillInTraining;
	responseSelector = sel;
	
	//charID = cid;
	charID = [cid copy];
	//[charID retain];
	
	[data setLength:0];
	
	NSString* body = [NSString stringWithFormat:@"userid=%@&apikey=%@&characterid=%@", userID, apiKey, cid];
	
	[self doPost:@"http://api.eve-online.com/char/SkillInTraining.xml.aspx" withBody:body];
}


- (void)connection:(NSURLConnection *)c didReceiveResponse:(NSURLResponse *)response
{
	NSHTTPURLResponse* resp = (NSHTTPURLResponse*)response;	
    [data setLength:0];	
	statusCode = [resp statusCode];
	
	if ( [resp statusCode] != 200 )
	{
		NSLog(@"got response: %d", [resp statusCode]);
		[c cancel];
		conn = nil;
		
		[responseDelegate performSelector:responseSelector withObject:self withObject:nil];
	}
}

- (void)connection:(NSURLConnection *)c didReceiveData:(NSData *)d
{
    // append the new data to the receivedData
    // receivedData is declared as a method instance elsewhere
    [data appendData:d];
}

- (void)connection:(NSURLConnection *)c
  didFailWithError:(NSError *)error
{
    [c release];
	conn = nil;
			
    NSLog(@"Connection failed! Error - %@ %@",
          [error localizedDescription],
          [[error userInfo] objectForKey:NSErrorFailingURLStringKey]);

	[responseDelegate performSelector:responseSelector withObject:self withObject:nil];
}



- (NSDictionary*) handleCharacterList
{
	CharListParser* clp = [[CharListParser alloc] init];
	NSDictionary* chars = [clp parseXml:data];
	[chars retain];
	[clp release];
	return chars;
}


- (id) handleCharacter
{
	CharacterParser* cp = [[CharacterParser alloc] init];
	Character* c = [cp parseXml:data];
	[c retain];
	[cp release];
	
	if ( c != nil )
	{		
		return c;
	}
	else
	{
		return nil;
	}
}


- (id) handleSkillInTraining
{	
	TrainingSkillParser* tsp = [[TrainingSkillParser alloc] init];
	NSDictionary* skilldict = [tsp parseXml:data];
	[skilldict retain];
	[tsp release];
	return skilldict;
}



- (void)connectionDidFinishLoading:(NSURLConnection *)c
{
	[c release];
	conn = nil;
	
    NSLog(@"Succeeded! Received %d bytes of data", [data length]);

	id responseObject = nil;
	switch ( requestType )
	{
		case EVEAPIRequestTypeCharacterList:
			responseObject = [self handleCharacterList];
			break;
		case EVEAPIRequestTypeCharacter:
			responseObject = [self handleCharacter];
			break;
		case EVEAPIRequestTypeSkillInTraining:
			responseObject = [self handleSkillInTraining];
			break;
		default:
			NSLog(@"unknown request type");
	}
		
	[responseDelegate performSelector:responseSelector withObject:self withObject:responseObject];
	if ( responseObject != nil ) [responseObject release];
}


- (void)dealloc
{
	NSLog(@"%s 0x%x", __FUNCTION__, self);
	
	WIPE( userID)
	WIPE( apiKey)
	WIPE( charID)
	WIPE( data)
	WIPE( conn)

	[super dealloc];
}


@end
